// #include "include/muduo/net/TcpServer.h"
// #include "include/muduo/net/TcpConnection.h"
// #include "include/muduo/net/EventLoop.h"
// #include "include/muduo/proto/codec.h"
// #include "include/muduo/proto/dispatcher.h"
// #include "include/muduo/base/Logging.h"     //不加incllude可以吗
// #include "include/muduo/base/Mutex.h"
// #include "protocol.pb.h"
#include <muduo/net/TcpServer.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/net/EventLoop.h>
#include <muduo/proto/codec.h>
#include <muduo/proto/dispatcher.h>
#include <muduo/base/Logging.h>
#include <muduo/base/Mutex.h>
#include "protocol.pb.h"

#include <memory>
#include <iostream>
#include <functional>

using namespace std::placeholders;
class Server
{
    typedef std::shared_ptr<google::protobuf::Message> MessagePtr;
    typedef std::shared_ptr<trans_add::TranslateRequest> TranslateRequestPtr;
    typedef std::shared_ptr<trans_add::AddRequest> AddRequestPtr;
public:
    Server(uint16_t port)
        :_server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port), "Server", muduo::net::TcpServer::kReusePort)
        ,_dispatcher(std::bind(&Server::onUnknownMessage, this, _1, _2, _3))
        ,_codec(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, _1, _2,_3))
    {
        _dispatcher.registerMessageCallback<trans_add::TranslateRequest>(std::bind(&Server::OnTranslateCallback, this, _1, _2, _3));
        _dispatcher.registerMessageCallback<trans_add::AddRequest>(std::bind(&Server::OnAddCallback, this, _1, _2, _3));
        _server.setConnectionCallback(std::bind(&Server::OnConnectionCallback, this, _1));
        _server.setMessageCallback(std::bind(&ProtobufCodec::onMessage, &_codec, _1, _2, _3));
    }
    void Start()
    {
        _server.start();
        _baseloop.loop();
    }
private:
    std::string Transform(const std::string& str)
    {
        static std::unordered_map<std::string, std::string> dict = {
            {"apple", "苹果"},
            {"banana", "香蕉"},
            {"pear", "梨"}
        };
        auto iter = dict.find(str);
        if(iter == dict.end())
            return "没找到...";
        else return iter->second;
    }

    void OnTranslateCallback(const muduo::net::TcpConnectionPtr& conn,
                                const TranslateRequestPtr& message,
                                muduo::Timestamp)
    {
        const std::string request = message->request();
        std::string val = Transform(request);
        trans_add::TranslateResponse response;
        response.set_response(val);
        _codec.send(conn, response);
    }

    void OnAddCallback(const muduo::net::TcpConnectionPtr& conn,
                                const AddRequestPtr& message,
                                muduo::Timestamp)
    {
        int num1 = message->num1();
        int num2 = message->num2();
        int result = num1 + num2;
        trans_add::AddResponse response;
        response.set_result(result);
        _codec.send(conn, response);
    }
    void onUnknownMessage(const muduo::net::TcpConnectionPtr& conn,
                        const MessagePtr& message,
                        muduo::Timestamp)
    {
        LOG_INFO << "onUnknownMessage: " << message->GetTypeName();
        conn->shutdown();
    }
    void OnConnectionCallback(const muduo::net::TcpConnectionPtr& conn)
    {
        if(conn->connected())
            std::cout << "链接成功" << std::endl;
        else std::cout << "链接断开" << std::endl;
    }
private:
    muduo::net::EventLoop _baseloop;
    muduo::net::TcpServer _server;
    ProtobufDispatcher _dispatcher;
    ProtobufCodec _codec;
};

int main(int argc, char* argv[])
{
    std::unique_ptr<Server> svr = std::make_unique<Server>(static_cast<uint16_t>(std::stoi(argv[1])));
    svr->Start();
}